<div class="content-section introduction">
    <div class="feature-intro">
        <h1>AutoComplete</h1>
        <p>AutoComplete is an input component that provides real-time suggestions when being typed.</p>
    </div>
    <app-demoActions github="autocomplete" stackblitz="autocomplete-demo"></app-demoActions>
</div>

<div class="content-section implementation">
    <div class="card">
        <h5>Basic</h5>
        <p-autoComplete [(ngModel)]="selectedCountry" [showEmptyMessage]="true" [suggestions]="filteredCountries" (completeMethod)="filterCountry($event)" field="name" [minLength]="1"></p-autoComplete>

        <h5>Dropdown and Templating</h5>
        <p-autoComplete [(ngModel)]="selectedCountryAdvanced" [suggestions]="filteredCountries" (completeMethod)="filterCountry($event)" field="name" [dropdown]="true">
            <ng-template let-country pTemplate="item">
                <div class="country-item">
                    <img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + country.code.toLowerCase()" />
                    <div>{{country.name}}</div>
                </div>
            </ng-template>
        </p-autoComplete>

        <h5>Grouped</h5>
        <p-autoComplete [(ngModel)]="selectedCity" [group]="true" [suggestions]="filteredGroups" (completeMethod)="filterGroupedCity($event)" field="label" [dropdown]="true">
            <ng-template let-group pTemplate="group">
                <div class="flex align-items-center">
                    <img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'mr-2 flag flag-' + group.value" style="width: 20px"/>
                    <span>{{group.label}}</span>
                </div>
            </ng-template>
        </p-autoComplete>

        <h5>Virtual Scroll (10000 Items)</h5>
        <p-autoComplete [(ngModel)]="selectedItem" [virtualScroll]="true" [suggestions]="filteredItems" [virtualScrollItemSize]="34" (completeMethod)="filterItems($event)" field="label" [dropdown]="true">
        </p-autoComplete>

        <h5>Multiple</h5>
        <span class="p-fluid">
            <p-autoComplete [(ngModel)]="selectedCountries" [suggestions]="filteredCountries" (completeMethod)="filterCountry($event)" field="name" [multiple]="true">
            </p-autoComplete>
        </span>
    </div>
</div>

<div class="content-section documentation">
    <p-tabView>
        <p-tabPanel header="Documentation">
            <h5>Import</h5>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
import &#123;AutoCompleteModule&#125; from 'primeng/autocomplete';
</app-code>

            <h5>Getting Started</h5>
            <p>AutoComplete uses ngModel for two-way binding, requires a list of suggestions and a completeMethod to query for the results. The completeMethod
            gets the query text as event.query property and should update the suggestions with the search results.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete [(ngModel)]="text" [suggestions]="results" (completeMethod)="search($event)"&gt;&lt;/p-autoComplete&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class AutoCompleteDemo &#123;

    text: string;

    results: string[];

    search(event) &#123;
        this.mylookupservice.getResults(event.query).then(data => &#123;
            this.results = data;
        &#125;);
    &#125;

&#125;
</app-code>

            <h5>Change Detection of Suggestions</h5>
            <p>AutoComplete uses setter based checking to realize if the suggestions has changed to update the UI. In order this to work, your changes such as adding or removing a record
                should always create a new array reference instead of manipulating an existing array as Angular does not trigger setters if the reference does not change.
            </p>

            <p>Note that if no suggestions are available after searching, provide an empty array instead of a null value.</p>

            <h5>Model Driven Forms</h5>
            <p>AutoComplete can be used in a model driven form as well.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete formControlName="city" [suggestions]="results" (completeMethod)="search($event)"&gt;&lt;/p-autoComplete&gt;
</app-code>

            <h5>Dropdown</h5>
            <p>Enabling <i>dropdown</i> property displays a button next to the input field where click behavior of the button is defined using dropdownMode
                property that takes "blank" or "current" as possible values. "blank" is the default mode to send a query with an empty string
                whereas "current" setting sends a query with the current value of the input.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete [(ngModel)]="text" [suggestions]="results" (completeMethod)="search($event)"
            [dropdown]="true"&gt;&lt;/p-autoComplete&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class AutoCompleteDemo &#123;

    text: string;

    results: string[];

    search(event) &#123;
        this.mylookupservice.getResults(event.query).then(data => &#123;
            this.results = data;
        &#125;);
    &#125;

    handleDropdown(event) &#123;
        //event.query = current value in input field
    &#125;

&#125;
</app-code>

            <h5>Multiple Selection</h5>
            <p>Multiple mode is enabled using <i>multiple</i> property to select more than one value from the autocomplete. In this case, value reference should be an array.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete [(ngModel)]="texts" [suggestions]="results" (completeMethod)="search($event)" [multiple]="true"&gt;&lt;/p-autoComplete&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class AutoCompleteDemo &#123;

    texts: string[];

    results: string[];

    search(event) &#123;
        this.mylookupservice.getResults(event.query).then(data => &#123;
            this.results = data;
        &#125;);
    &#125;

&#125;
</app-code>

            <h5>Objects</h5>
            <p>AutoComplete can also work with objects using the <i>field</i> property that defines the label to display as a suggestion. The value passed to the model would still be the
            object instance of a suggestion. Here is an example with a Country object that has name and code fields such as &#123;name:"United States",code:"USA"&#125;.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete [(ngModel)]="val" [suggestions]="results" (completeMethod)="search($event)" field="name"&gt;&lt;/p-autoComplete&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class AutoCompleteDemo &#123;

    val: country;

    results: country[];

    search(event) &#123;
        this.countrylookupservice.getResults(event.query).then(data => &#123;
            this.results = data;
        &#125;);
    &#125;

&#125;
</app-code>

            <h5>Force Selection</h5>
            <p>ForceSelection mode validates the manual input to check whether it also exists in the suggestions list, if not the input value is cleared
            to make sure the value passed to the model is always one of the suggestions.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete [(ngModel)]="val" [suggestions]="results" (completeMethod)="search($event)" [forceSelection]="true"&gt;&lt;/p-autoComplete&gt;
</app-code>

            <h5>Templating</h5>
            <p>Item ng-template allows displaying custom content inside the suggestions panel. The local ng-template variable passed to the ng-template is an object in the suggestions array.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete [(ngModel)]="brand" [suggestions]="filteredBrands" (completeMethod)="filterBrands($event)"&gt;
    &lt;ng-template let-brand pTemplate="item"&gt;
            &lt;img src="assets/showcase/images/demo/car/&#123;&#123;brand&#125;&#125;.png" style="width:32px;display:inline-block;margin:5px 0 2px 5px"/&gt;
            &lt;div style="font-size:18px;float:right;margin:10px 10px 0 0"&gt;&#123;&#123;brand&#125;&#125;&lt;/div&gt;
    &lt;/ng-template&gt;
&lt;/p-autoComplete&gt;
</app-code>

            <p>In multiple mode, selected item can be customized using selectedItem ng-template. Note that this
                template is not supported in single mode. In addition when grouping is enabled, <i>group</i> template is available
                to customize the option groups. All templates get the option instance as the default local template variable.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete [(ngModel)]="texts" [suggestions]="results" (completeMethod)="search($event)" [multiple]="true"&gt;
    &lt;ng-template let-value pTemplate="selectedItem"&gt;
        &lt;span style="font-size:18px"&gt;&gt;&#123;&#123;value&#125;&#125;&lt;&lt;/span&gt;
    &lt;/ng-template&gt;
&lt;/p-autoComplete&gt;
</app-code>

            <h5>Animation Configuration</h5>
            <p>Transition of the open and hide animations can be customized using the showTransitionOptions and hideTransitionOptions properties,
                example below disables the animations altogether.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-autoComplete [showTransitionOptions]="'0ms'" [hideTransitionOptions]="'0ms'" [(ngModel)]="texts" [suggestions]="results" (completeMethod)="search($event)"&gt;&lt;/p-autoComplete&gt;
</app-code>

            <h5>Properties</h5>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Type</th>
                            <th>Default</th>
                            <th>Description</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>suggestions</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of suggestions to display.</td>
                        </tr>
                        <tr>
                            <td>field</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Field of a suggested object to resolve and display.</td>
                        </tr>
                        <tr>
                            <td>scrollHeight</td>
                            <td>string</td>
                            <td>200px</td>
                            <td>Maximum height of the suggestions panel.</td>
                        </tr>
                        <tr>
                            <td>dropdown</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Displays a button next to the input field when enabled.</td>
                        </tr>
                        <tr>
                            <td>multiple</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Specifies if multiple values can be selected.</td>
                        </tr>
                        <tr>
                            <td>dropdownIcon</td>
                            <td>string</td>
                            <td>pi pi-chevron-down</td>
                            <td>Icon class of the dropdown icon.</td>
                        </tr>
                        <tr>
                            <td>minLength</td>
                            <td>number</td>
                            <td>1</td>
                            <td>Minimum number of characters to initiate a search.</td>
                        </tr>
                        <tr>
                            <td>delay</td>
                            <td>number</td>
                            <td>300</td>
                            <td>Delay between keystrokes to wait before sending a query.</td>
                        </tr>
                        <tr>
                            <td>completeOnFocus</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether to run a query when input receives focus.</td>
                        </tr>
                        <tr>
                            <td>style</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Inline style of the component.</td>
                        </tr>
                        <tr>
                            <td>inputStyle</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Inline style of the input field.</td>
                        </tr>
                        <tr>
                            <td>panelStyle</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Inline style of the overlay panel element.</td>
                        </tr>
                        <tr>
                            <td>styleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Style class of the component.</td>
                        </tr>
                        <tr>
                            <td>inputStyleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Inline style of the input field.</td>
                        </tr>
                        <tr>
                            <td>panelStyleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Style class of the overlay panel element.</td>
                        </tr>
                        <tr>
                            <td>inputId</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Identifier of the focus input to match a label defined for the component.</td>
                        </tr>
                        <tr>
                            <td>name</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Name of the input element.</td>
                        </tr>
                        <tr>
                            <td>optionGroupLabel</td>
                            <td>string</td>
                            <td>label</td>
                            <td>Name of the label field of an option group.</td>
                        </tr>
                        <tr>
                            <td>group</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether to display options as grouped when nested options are provided.</td>
                        </tr>
                        <tr>
                            <td>optionGroupChildren</td>
                            <td>string</td>
                            <td>items</td>
                            <td>Name of the options field of an option group.</td>
                        </tr>
                        <tr>
                            <td>placeholder</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Hint text for the input field.</td>
                        </tr>
                        <tr>
                            <td>readonly</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When present, it specifies that the input cannot be typed.</td>
                        </tr>
                        <tr>
                            <td>disabled</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When present, it specifies that the component should be disabled.</td>
                        </tr>
                        <tr>
                            <td>maxlength</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Maximum number of character allows in the input field.</td>
                        </tr>
                        <tr>
                            <td>size</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Size of the input field.</td>
                        </tr>
                        <tr>
                            <td>appendTo</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Target element to attach the overlay, valid values are "body" or a local ng-template variable of another element (note: use binding with brackets for template variables, e.g. [appendTo]="mydiv" for a div element having #mydiv as variable name).</td>
                        </tr>
                        <tr>
                            <td>tabindex</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Index of the element in tabbing order.</td>
                        </tr>
                        <tr>
                            <td>dataKey</td>
                            <td>string</td>
                            <td>null</td>
                            <td>A property to uniquely identify a value in options.</td>
                        </tr>
                        <tr>
                            <td>autoHighlight</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When enabled, highlights the first item in the list by default.</td>
                        </tr>
                        <tr>
                            <td>type</td>
                            <td>string</td>
                            <td>text</td>
                            <td>Type of the input, defaults to "text".</td>
                        </tr>

                        <tr>
                            <td>showEmptyMessage</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether to show the empty message or not.</td>
                        </tr>
                        <tr>
                            <td>emptyMessage</td>
                            <td>string</td>
                            <td>No records found.</td>
                            <td>Text to display when there is no data. Defaults to global value in i18n translation configuration.</td>
                        </tr>
                        <tr>
                            <td>immutable</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Defines how the suggestions should be manipulated. More information is available at "Change Detection" section above.</td>
                        </tr>
                        <tr>
                            <td>required</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When present, it specifies that an input field must be filled out before submitting the form.</td>
                        </tr>
                        <tr>
                            <td>autofocus</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When present, it specifies that the component should automatically get focus on load.</td>
                        </tr>
                        <tr>
                            <td>forceSelection</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When present, autocomplete clears the manual input if it does not match of the suggestions to force only
                                accepting values from the suggestions.</td>
                        </tr>
                        <tr>
                            <td>dropdownMode</td>
                            <td>string</td>
                            <td>blank</td>
                            <td>Specifies the behavior dropdown button. Default "blank" mode
                                    sends an empty string and "current" mode sends the input value.</td>
                        </tr>
                        <tr>
                            <td>baseZIndex</td>
                            <td>number</td>
                            <td>0</td>
                            <td>Base zIndex value to use in layering.</td>
                        </tr>
                        <tr>
                            <td>autoZIndex</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether to automatically manage layering.</td>
                        </tr>
                        <tr>
                            <td>showTransitionOptions</td>
                            <td>string</td>
                            <td>.12s cubic-bezier(0, 0, 0.2, 1)</td>
                            <td>Transition options of the show animation.</td>
                        </tr>
                        <tr>
                            <td>hideTransitionOptions</td>
                            <td>string</td>
                            <td>.1s linear</td>
                            <td>Transition options of the hide animation.</td>
                        </tr>
                        <tr>
                            <td>ariaLabel</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Defines a string that labels the input for accessibility.</td>
                        </tr>
                        <tr>
                            <td>ariaLabelledBy</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Specifies one or more IDs in the DOM that labels the input field.</td>
                        </tr>
                        <tr>
                            <td>dropdownAriaLabel</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Defines a string that labels the dropdown button for accessibility.</td>
                        </tr>
                        <tr>
                            <td>unique</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Ensures uniqueness of selected items on multiple mode.</td>
                        </tr>
                        <tr>
                            <td>autocomplete</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Used to define a string that autocomplete attribute the current element.</td>
                        </tr>
                        <tr>
                            <td>showClear</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When enabled, a clear icon is displayed to clear the value.</td>
                        </tr>
                        <tr>
                            <td>virtualScroll</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether the data should be loaded on demand during scroll.</td>
                        </tr>
                        <tr>
                            <td>virtualScrollItemSize</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Height of an item in the list for VirtualScrolling.</td>
                        </tr>
                        <tr>
                            <td>virtualScrollOptions</td>
                            <td>ScrollerOptions</td>
                            <td>false</td>
                            <td>Whether to use the scroller feature. The properties of <a href="#" [routerLink]="['/theming']">scroller</a> component can be used like an object in it.</td>
                        </tr>
                        <tr>
                            <td>lazy</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Defines if data is loaded and interacted with in lazy manner.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Events</h5>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Parameters</th>
                            <th>Description</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>completeMethod</td>
                            <td>
                                event.originalEvent: browser event <br>
                                event.query: Value to search with
                            </td>
                            <td>Callback to invoke to search for suggestions.</td>
                        </tr>
                        <tr>
                            <td>onFocus</td>
                            <td>event: Browser event</td>
                            <td>Callback to invoke when autocomplete gets focus.</td>
                        </tr>
                        <tr>
                            <td>onBlur</td>
                            <td>event: Browser event</td>
                            <td>Callback to invoke when autocomplete loses focus.</td>
                        </tr>
                        <tr>
                            <td>onKeyUp</td>
                            <td>event: Browser event</td>
                            <td>Callback to invoke when a user releases a key.</td>
                        </tr>
                        <tr>
                            <td>onSelect</td>
                            <td>
                                value: Selected value
                            </td>
                            <td>Callback to invoke when a suggestion is selected.</td>
                        </tr>
                        <tr>
                            <td>onUnselect</td>
                            <td>
                                value: Unselected value in multiple mode
                            </td>
                            <td>Callback to invoke when a selected value is removed.</td>
                        </tr>
                        <tr>
                            <td>onDropdownClick</td>
                            <td>
                                event.originalEvent: browser event <br>
                                event.query: Current value of the input field
                            </td>
                            <td>Callback to invoke when dropdown button is clicked.</td>
                        </tr>
                        <tr>
                            <td>onClear</td>
                            <td>-</td>
                            <td>Callback to invoke when input field is cleared.</td>
                        </tr>
                        <tr>
                            <td>onShow</td>
                            <td>event: Animation event</td>
                            <td>Callback to invoke when autocomplete overlay gets visible.</td>
                        </tr>
                        <tr>
                            <td>onHide</td>
                            <td>-</td>
                            <td>Callback to invoke when autocomplete overlay gets hidden.</td>
                        </tr>
                        <tr>
                            <td>onLazyLoad</td>
                            <td>event.first: First index of the new data range to be loaded.<br/>
                                event.last: Last index of the new data range to be loaded.
                            </td>
                            <td>Callback to invoke in lazy mode to load new data.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Templates</h5>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Parameters</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>item</td>
                            <td>$implicit: Data of the option <br />
                                index: Index of the option</td>
                        </tr>
                        <tr>
                            <td>group</td>
                            <td>$implicit: Group option</td>
                        </tr>
                        <tr>
                            <td>selectedItem</td>
                            <td>$implicit: value</td>
                        </tr>
                        <tr>
                            <td>header</td>
                            <td>-</td>
                        </tr>
                        <tr>
                            <td>footer</td>
                            <td>-</td>
                        </tr>
                        <tr>
                            <td>loader</td>
                            <td>options: Options of the scroller on loading. *This template can be used with virtualScroll.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Styling</h5>
            <p>Following is the list of structural style classes, for theming classes visit <a href="#" [routerLink]="['/theming']">theming page</a>.</p>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Element</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>p-autocomplete</td>
                            <td>Container element</td>
                        </tr>
                        <tr>
                            <td>p-autocomplete-panel</td>
                            <td>Overlay panel of suggestions.</td>
                        </tr>
                        <tr>
                            <td>p-autocomplete-items</td>
                            <td>List container of suggestions.</td>
                        </tr>
                        <tr>
                            <td>p-autocomplete-item</td>
                            <td>List item of a suggestion.</td>
                        </tr>
                        <tr>
                            <td>p-autocomplete-token</td>
                            <td>Element of a selected item in multiple mode.</td>
                        </tr>
                        <tr>
                            <td>p-autocomplete-token-icon</td>
                            <td>Close icon element of a selected item in multiple mode.</td>
                        </tr>
                        <tr>
                            <td>p-autocomplete-token-label</td>
                            <td>Label of a selected item in multiple mode.</td>
                        </tr>
                        <tr>
                            <td>p-autocomplete-loader</td>
                            <td>Loader icon.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Dependencies</h5>
            <p>None.</p>
        </p-tabPanel>

        <p-tabPanel header="Source">
            <a href="https://github.com/primefaces/primeng/tree/master/src/app/showcase/components/autocomplete" class="btn-viewsource" target="_blank">
                <span>View on GitHub</span>
            </a>
            <a href="https://stackblitz.com/edit/primeng-autocomplete-demo" class="btn-viewsource" style="margin-left: .5em;" target="_blank">
                <span>Edit in StackBlitz</span>
            </a>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;div class="card"&gt;
    &lt;h5&gt;Basic&lt;/h5&gt;
    &lt;p-autoComplete [(ngModel)]="selectedCountry" [showEmptyMessage]="true" [suggestions]="filteredCountries" (completeMethod)="filterCountry($event)" field="name" [minLength]="1"&gt;&lt;/p-autoComplete&gt;

    &lt;h5&gt;Dropdown and Templating&lt;/h5&gt;
    &lt;p-autoComplete [(ngModel)]="selectedCountryAdvanced" [suggestions]="filteredCountries" (completeMethod)="filterCountry($event)" field="name" [dropdown]="true"&gt;
        &lt;ng-template let-country pTemplate="item"&gt;
            &lt;div class="country-item"&gt;
                &lt;img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + country.code.toLowerCase()" /&gt;
                &lt;div&gt;&#123;&#123;country.name&#125;&#125;&lt;/div&gt;
            &lt;/div&gt;
        &lt;/ng-template&gt;
    &lt;/p-autoComplete&gt;

    &lt;h5&gt;Grouped&lt;/h5&gt;
    &lt;p-autoComplete [(ngModel)]="selectedCity" [group]="true" [suggestions]="filteredGroups" (completeMethod)="filterGroupedCity($event)" field="label" [dropdown]="true"&gt;
        &lt;ng-template let-group pTemplate="group"&gt;
            &lt;div class="flex align-items-center"&gt;
                &lt;img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'mr-2 flag flag-' + group.value" style="width: 20px"/&gt;
                &lt;span&gt;&#123;&#123;group.label&#125;&#125;&lt;/span&gt;
            &lt;/div&gt;
        &lt;/ng-template&gt;
    &lt;/p-autoComplete&gt;

    &lt;h5&gt;Virtual Scroll (10000 Items)&lt;/h5&gt;
    &lt;p-autoComplete [(ngModel)]="selectedItem" [virtualScroll]="true" [suggestions]="filteredItems" [virtualScrollItemSize]="34" (completeMethod)="filterItems($event)" field="label" [dropdown]="true"&gt;
    &lt;/p-autoComplete&gt;

    &lt;h5&gt;Multiple&lt;/h5&gt;
    &lt;span class="p-fluid"&gt;
        &lt;p-autoComplete [(ngModel)]="selectedCountries" [suggestions]="filteredCountries" (completeMethod)="filterCountry($event)" field="name" [multiple]="true"&gt;
        &lt;/p-autoComplete&gt;
    &lt;/span&gt;
&lt;/div&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class AutoCompleteDemo &#123;

    selectedCountry: any;

    selectedCity: any;

    selectedItem: any;

    countries: any[];

    items: any[];

    filteredCountries: any[];

    filteredItems: any[];

    selectedCountries: any[];

    selectedCountryAdvanced: any[];

    filteredBrands: any[];

    groupedCities: SelectItemGroup[];

    filteredGroups: any[];

    constructor(private countryService: CountryService, private filterService: FilterService) &#123; &#125;

    ngOnInit() &#123;
        this.countryService.getCountries().then(countries =&gt; &#123;
            this.countries = countries;
        &#125;);

        this.groupedCities = [
            &#123;
                label: 'Germany', value: 'de',
                items: [
                    &#123;label: 'Berlin', value: 'Berlin'&#125;,
                    &#123;label: 'Frankfurt', value: 'Frankfurt'&#125;,
                    &#123;label: 'Hamburg', value: 'Hamburg'&#125;,
                    &#123;label: 'Munich', value: 'Munich'&#125;
                ]
            &#125;,
            &#123;
                label: 'USA', value: 'us',
                items: [
                    &#123;label: 'Chicago', value: 'Chicago'&#125;,
                    &#123;label: 'Los Angeles', value: 'Los Angeles'&#125;,
                    &#123;label: 'New York', value: 'New York'&#125;,
                    &#123;label: 'San Francisco', value: 'San Francisco'&#125;
                ]
            &#125;,
            &#123;
                label: 'Japan', value: 'jp',
                items: [
                    &#123;label: 'Kyoto', value: 'Kyoto'&#125;,
                    &#123;label: 'Osaka', value: 'Osaka'&#125;,
                    &#123;label: 'Tokyo', value: 'Tokyo'&#125;,
                    &#123;label: 'Yokohama', value: 'Yokohama'&#125;
                ]
            &#125;
        ];

        this.items = [];
        for (let i = 0; i &lt; 10000; i++) &#123;
            this.items.push(&#123;label: 'Item ' + i, value: 'Item ' + i&#125;);
        &#125;
    &#125;

    filterCountry(event) &#123;
        //in a real application, make a request to a remote url with the query and return filtered results, for demo we filter at client side
        let filtered : any[] = [];
        let query = event.query;

        for(let i = 0; i &lt; this.countries.length; i++) &#123;
            let country = this.countries[i];
            if (country.name.toLowerCase().indexOf(query.toLowerCase()) == 0) &#123;
                filtered.push(country);
            &#125;
        &#125;

        this.filteredCountries = filtered;
    &#125;

    filterItems(event) &#123;
        //in a real application, make a request to a remote url with the query and return filtered results, for demo we filter at client side
        let filtered : any[] = [];
        let query = event.query;

        for(let i = 0; i &lt; this.items.length; i++) &#123;
            let item = this.items[i];
            if (item.label.toLowerCase().indexOf(query.toLowerCase()) == 0) &#123;
                filtered.push(item);
            &#125;
        &#125;

        this.filteredItems = filtered;
    &#125;

    filterGroupedCity(event) &#123;
        let query = event.query;
        let filteredGroups = [];

        for (let optgroup of this.groupedCities) &#123;
            let filteredSubOptions = this.filterService.filter(optgroup.items, ['label'], query, "contains");
            if (filteredSubOptions && filteredSubOptions.length) &#123;
                filteredGroups.push(&#123;
                    label: optgroup.label,
                    value: optgroup.value,
                    items: filteredSubOptions
                &#125;);
            &#125;
        &#125;

        this.filteredGroups = filteredGroups;
    &#125;
&#125;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
@Injectable()
export class CountryService &#123;

    constructor(private http: Http) &#123;&#125;

    getCountries() &#123;
        return this.http.get('showcase/resources/data/countries.json')
                    .toPromise()
                    .then(res => &lt;any[]&gt; res.json().data)
                    .then(data => &#123; return data; &#125;);
    &#125;
&#125;
</app-code>
        </p-tabPanel>
        <p-tabPanel header="StackBlitz">
            <ng-template pTemplate="content">
                <iframe src="https://stackblitz.com/edit/primeng-autocomplete-demo?embed=1" style="width: 100%; height: 768px; border: none;"></iframe>
            </ng-template>
        </p-tabPanel>
    </p-tabView>
</div>
